package com.xiaojf.xsso.client.filter;

import cn.hutool.json.JSONUtil;
import com.xiaojf.xsso.client.service.SsoClientService;
import com.xiaojf.xsso.common.constant.SsoConstant;
import com.xiaojf.xsso.common.model.CommonResult;
import com.xiaojf.xsso.common.model.SsoUser;
import com.xiaojf.xsso.common.path.impl.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 拦截所有token认证的请求
 *
 * @author Ade.Xiao 2021/1/29 15:43
 */
public class SsoTokenFilter extends HttpServlet implements Filter {
    private static final long serialVersionUID = 8519320212470805636L;

    private static final AntPathMatcher antPathMatcher = new AntPathMatcher();

    private String ssoServer;
    private String logoutPath;
    private String excludedPaths;
    private SsoClientService clientService;

    /**
     * 构造函数
     *
     * @param ssoServer     统一认证地址
     * @param logoutPath    登出地址
     * @param excludedPaths 不拦截路径，多个用英文逗号分隔
     * @param clientService 客户端逻辑实现
     * @author Ade.Xiao 2021/1/30 16:38
     */
    public SsoTokenFilter(String ssoServer, String logoutPath, String excludedPaths, SsoClientService clientService) {
        this.ssoServer = ssoServer;
        this.logoutPath = logoutPath;
        this.excludedPaths = excludedPaths;
        this.clientService = clientService;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;

        // make url
        String servletPath = req.getServletPath();

        // excluded path check
        if (excludedPaths != null && excludedPaths.trim().length() > 0) {
            for (String excludedPath : excludedPaths.split(",")) {
                String uriPattern = excludedPath.trim();

                // 支持ANT表达式
                if (antPathMatcher.match(uriPattern, servletPath)) {
                    // excluded path, allow
                    chain.doFilter(request, response);
                    return;
                }

            }
        }

        // logout filter
        if (logoutPath != null && logoutPath.trim().length() > 0 && logoutPath.equals(servletPath)) {
            // logout
            clientService.logout(req.getHeader(SsoConstant.SSO_SESSIONID));
            // response
            res.setStatus(HttpServletResponse.SC_OK);
            res.setContentType("application/json;charset=UTF-8");
            res.getWriter().println(JSONUtil.toJsonStr(CommonResult.SUCCESS));
            return;
        }

        // login filter
        SsoUser ssoUser = clientService.loginCheck(SsoConstant.AUTH_TYPE_APP, req.getHeader(SsoConstant.SSO_SESSIONID));
        if (ssoUser == null) {

            // response
            res.setStatus(HttpServletResponse.SC_OK);
            res.setContentType("application/json;charset=UTF-8");
            res.getWriter().println(JSONUtil.toJsonStr(new CommonResult(SsoConstant.SSO_LOGIN_FAIL_RESULT.getCode(), SsoConstant.SSO_LOGIN_FAIL_RESULT.getMsg())));

            return;
        }

        // ser sso user
        request.setAttribute(SsoConstant.SSO_USER, ssoUser);

        // already login, allow
        chain.doFilter(request, response);
        return;
    }
}
